package gateway

import (
	"github.com/gin-gonic/gin"
	"hobby-mate/cache"
	"hobby-mate/common"
	"net/http"
	"regexp"
)

const loginApi = "/api/sys/open/account/_login"
const error401 = "您无权限访问"
const limitError = "接口限流,请稍后再试"

var openPattern = regexp.MustCompile(`^/api/.+/open/.+$`)
var tokenPattern = regexp.MustCompile(`^/api/.+/token/.+$`)

// ApiCenter 网关中心
// 1.白名单 2.黑名单 3.处理token接口请求 4.登录cookie处理
func ApiCenter(routerServer *gin.Context) {
	IpWhiteList()
	IpBlackList()
	handlerApiRequest(routerServer)
	routerServer.Next()
	HandlerLoginCookie(routerServer)
}

// IpWhiteList 白名单
func IpWhiteList() {

}

// IpBlackList 黑名单
func IpBlackList() {

}

// handlerApiRequest 处理token接口请求
func handlerApiRequest(routerServer *gin.Context) {
	if (openPattern.MatchString(routerServer.Request.RequestURI) &&
		((routerServer.Request.Method == http.MethodPost && routerServer.Request.RequestURI != loginApi) ||
			routerServer.Request.Method == http.MethodPut ||
			routerServer.Request.Method == http.MethodDelete)) ||
		tokenPattern.MatchString(routerServer.Request.RequestURI) {
		SetUserInfos(routerServer)
	}
}

// HandlerLoginCookie 登录cookie处理
func HandlerLoginCookie(routerServer *gin.Context) {
	if routerServer.Request.RequestURI != loginApi {
		return
	}
	//获取data数据
	data, exist := routerServer.Get("data")
	if !exist {
		//此刻没有获取到data接口数据说明执行的是其他接口
		return
	}
	tokenValue, exist := data.(string)
	// 此刻没有获取到tokenValue说明接口被Abort()掉
	if !exist {
		return
	}
	_, exist = routerServer.Get("login_result")
	// 此刻没有获取到login_result说明接口被程序Error掉可能是mysql框架的内部错误
	if !exist {
		return
	}
	//设置cookie
	routerServer.SetCookie(
		"Token",
		tokenValue,
		60*60*24,
		"/",
		"/",
		false,
		true)
	// TODO：这个返回值应该是具体接口去处理，放在这里是因为要拦截_login接口的返回值不能放在这是因为如果其他过程返回了500错误，还会往下执行返回这个值==>gin的Abort()方法无法终止中间件的执行
	common.ReturnOkSuccess(routerServer, nil)
}

// SetUserInfos 给token接口校验token 获取用户信息
func SetUserInfos(routerServer *gin.Context) {
	tokenValue, err := routerServer.Cookie("Token")
	userInfo, err := common.CheckAndParseToken(tokenValue)
	if err != nil {
		authFail(routerServer)
	}
	//将用户信息存入缓存
	cache.UserInfos.AccountId = userInfo.AccountId
	cache.UserInfos.Username = userInfo.Username
}

// authFail token接口认证失败
func authFail(routerServer *gin.Context) {
	routerServer.AbortWithStatusJSON(http.StatusUnauthorized, common.ForBiddenErrorJSON)
}
